"""
市场数据模型
===========
定义市场数据相关的所有数据模型
"""

from typing import List, Optional
from datetime import datetime
from decimal import Decimal
from pydantic import Field
from .base_model import BaseModel, TimestampMixin
from .enums import MarketType, TimeFrame


class Ticker(TimestampMixin):
    """行情数据"""
    
    symbol: str = Field(
        description="交易对符号",
        example="BTCUSD"
    )
    
    market_type: MarketType = Field(
        description="市场类型"
    )
    
    last_price: Decimal = Field(
        description="最新价格",
        gt=0,
        decimal_places=8
    )
    
    bid_price: Optional[Decimal] = Field(
        default=None,
        description="买一价",
        gt=0,
        decimal_places=8
    )
    
    ask_price: Optional[Decimal] = Field(
        default=None,
        description="卖一价",
        gt=0,
        decimal_places=8
    )
    
    high_24h: Optional[Decimal] = Field(
        default=None,
        description="24小时最高价",
        gt=0,
        decimal_places=8
    )
    
    low_24h: Optional[Decimal] = Field(
        default=None,
        description="24小时最低价",
        gt=0,
        decimal_places=8
    )
    
    volume_24h: Optional[Decimal] = Field(
        default=None,
        description="24小时成交量",
        ge=0,
        decimal_places=8
    )
    
    change_24h: Optional[Decimal] = Field(
        default=None,
        description="24小时价格变化",
        decimal_places=8
    )
    
    change_percent_24h: Optional[float] = Field(
        default=None,
        description="24小时价格变化百分比"
    )
    
    @property
    def spread(self) -> Optional[Decimal]:
        """买卖价差"""
        if self.bid_price is not None and self.ask_price is not None:
            return self.ask_price - self.bid_price
        return None
    
    @property
    def mid_price(self) -> Optional[Decimal]:
        """中间价"""
        if self.bid_price is not None and self.ask_price is not None:
            return (self.bid_price + self.ask_price) / 2
        return None


class OHLCV(BaseModel):
    """K线数据"""
    
    symbol: str = Field(
        description="交易对符号"
    )
    
    timeframe: TimeFrame = Field(
        description="时间周期"
    )
    
    timestamp: datetime = Field(
        description="时间戳"
    )
    
    open_price: Decimal = Field(
        description="开盘价",
        gt=0,
        decimal_places=8
    )
    
    high_price: Decimal = Field(
        description="最高价",
        gt=0,
        decimal_places=8
    )
    
    low_price: Decimal = Field(
        description="最低价",
        gt=0,
        decimal_places=8
    )
    
    close_price: Decimal = Field(
        description="收盘价",
        gt=0,
        decimal_places=8
    )
    
    volume: Decimal = Field(
        description="成交量",
        ge=0,
        decimal_places=8
    )
    
    @property
    def price_change(self) -> Decimal:
        """价格变化"""
        return self.close_price - self.open_price
    
    @property
    def price_change_percent(self) -> float:
        """价格变化百分比"""
        if self.open_price == 0:
            return 0.0
        return float((self.close_price - self.open_price) / self.open_price * 100)
    
    @property
    def is_bullish(self) -> bool:
        """是否看涨（收盘价高于开盘价）"""
        return self.close_price > self.open_price
    
    @property
    def is_bearish(self) -> bool:
        """是否看跌（收盘价低于开盘价）"""
        return self.close_price < self.open_price


class OrderBookEntry(BaseModel):
    """订单簿条目"""
    
    price: Decimal = Field(
        description="价格",
        gt=0,
        decimal_places=8
    )
    
    quantity: Decimal = Field(
        description="数量",
        gt=0,
        decimal_places=8
    )
    
    @property
    def total_value(self) -> Decimal:
        """总价值"""
        return self.price * self.quantity


class OrderBook(TimestampMixin):
    """订单簿"""
    
    symbol: str = Field(
        description="交易对符号"
    )
    
    bids: List[OrderBookEntry] = Field(
        description="买单列表",
        default_factory=list
    )
    
    asks: List[OrderBookEntry] = Field(
        description="卖单列表", 
        default_factory=list
    )
    
    @property
    def best_bid(self) -> Optional[OrderBookEntry]:
        """最优买价"""
        return self.bids[0] if self.bids else None
    
    @property
    def best_ask(self) -> Optional[OrderBookEntry]:
        """最优卖价"""
        return self.asks[0] if self.asks else None
    
    @property
    def spread(self) -> Optional[Decimal]:
        """买卖价差"""
        best_bid = self.best_bid
        best_ask = self.best_ask
        if best_bid and best_ask:
            return best_ask.price - best_bid.price
        return None
    
    @property
    def mid_price(self) -> Optional[Decimal]:
        """中间价"""
        best_bid = self.best_bid
        best_ask = self.best_ask
        if best_bid and best_ask:
            return (best_bid.price + best_ask.price) / 2
        return None


class MarketData(BaseModel):
    """综合市场数据"""
    
    symbol: str = Field(description="交易对符号")
    ticker: Optional[Ticker] = Field(default=None, description="行情数据")
    order_book: Optional[OrderBook] = Field(default=None, description="订单簿")
    recent_trades: List[dict] = Field(default_factory=list, description="最近成交")
    
    class Config:
        arbitrary_types_allowed = True
